#include "Entities/PolygonEntity.h"
#include "Entities/BodyEntity.h"

using namespace cmn;
using namespace drawing;
using namespace editor_core;

PolygonEntity::PolygonEntity( BodyEntity* parentBody, const Transform& position ) :
	m_position( position ),
	m_parentBody( parentBody )
{}

PolygonEntity::~PolygonEntity() {}

bool CompareVertices( VertexEntity* const& vertexA, VertexEntity* const& vertexB ) {
	return Vec2::Counterclockwise( vertexA->GetPosition(), vertexB->GetPosition() );
}

void PolygonEntity::AddVertex( VertexEntity* vertex ) {
	m_childrenVertices.Add( vertex );
	m_childrenVertices.SortStable( CompareVertices );
}

void PolygonEntity::RemoveVertex( VertexEntity* vertex ) {
	m_childrenVertices.Remove( vertex );
}

void PolygonEntity::GetVertices( ICollection<VertexEntity*>& vertices ) const {
	vertices.Clear();
	for( IteratorPtr<VertexEntity*> verticesIter( m_childrenVertices );
			!verticesIter.IsEnd();
			verticesIter.Next() )
	{
		VertexEntity* vertex = verticesIter.Current();
		vertices.Add( vertex );
	}
}

void PolygonEntity::GetChildren( ICollection<IEntity*>& children ) const {
	children.Clear();
	for( IteratorPtr<VertexEntity*> verticesIter( m_childrenVertices );
			!verticesIter.IsEnd();
			verticesIter.Next() )
	{
		VertexEntity* vertex = verticesIter.Current();
		children.Add( vertex );
	}
}

void PolygonEntity::GetParents( ICollection<IEntity*>& parents ) const {
	parents.Clear();
	parents.Add( m_parentBody );
}

void PolygonEntity::GetProperties( ICollection<Property>& properties ) const {
	properties.Clear();

	Property position( 301, "Position", 0 );
	Property positionVec( 3011, "Vector", 0 );
	positionVec.AddChild( Property( 30111, "X", PropertyValue( m_position.Vec.X ) ) );
	positionVec.AddChild( Property( 30112, "Y", PropertyValue( m_position.Vec.Y ) ) );
	position.AddChild( positionVec );

	position.AddChild( Property( 3012, "Rotation", PropertyValue( m_position.Rot ) ) );
	position.AddChild( Property( 3013, "Scale", PropertyValue( m_position.Scale ) ) );

	properties.Add( position );
}

bool PolygonEntity::TryUpdateProperty( Property& property ) const {
	switch( property.GetKey() ) {
		case 301:
			return false;
		case 3011:
			return false;
		case 30111:
			property.SetValue( PropertyValue( m_position.Vec.X ) );
			return true;
		case 30112:
			property.SetValue( PropertyValue( m_position.Vec.Y ) );
			return true;
		case 3012:
			property.SetValue( PropertyValue( m_position.Rot ) );
			return true;
		case 3013:
			property.SetValue( PropertyValue( m_position.Scale ) );
			return true;
		default:
			return false;
	}
}

bool PolygonEntity::TryUpdateFromProperty( const Property& property ) {
	switch( property.GetKey() ) {
		case 301:
			return false;
		case 3011:
			return false;
		case 30111:
			m_position.Vec.X = property.GetValue().GetFloat();
			return true;
		case 30112:
			m_position.Vec.Y = property.GetValue().GetFloat();
			return true;
		case 3012:
			m_position.Rot = property.GetValue().GetFloat();
			return true;
		case 3013:
			m_position.Scale = property.GetValue().GetFloat();
			return true;
		default:
			return false;
	}
}

void PolygonEntity::Tick() {}

void PolygonEntity::DrawInner( IDrawer* drawer ) {
	Polygon polygon;

	Vector<VertexEntity*> vertexEntities;
	GetVertices( vertexEntities );
	for( IteratorPtr<VertexEntity*> verticesIter( vertexEntities );
			!verticesIter.IsEnd();
			verticesIter.Next() )
	{
		polygon.AddVertex( GetPosition() * verticesIter.Current()->GetPosition() );
	}

	drawer->DrawPolygon( polygon );
}

Vec2 PolygonEntity::Move( const Vec2& vector ) {
	m_position.Vec += vector;
	return vector;
}

void PolygonEntity::Delete() {
	m_parentBody->RemovePolygon( this );
}

void PolygonEntity::Undelete() {
	m_parentBody->AddPolygon( this );
}

bool PolygonEntity::Contains( const Vec2& point ) const {
	int count = m_childrenVertices.GetLength();

	Vec2 vertexA = m_position * m_childrenVertices[count - 1]->GetPosition();
	for( int i = 0; i < count; ++i ) {
		Vec2 vertexB = m_position * m_childrenVertices[i]->GetPosition();
		Vec2 aToB = vertexB - vertexA;
		Vec2 aToPoint = point - vertexA;

		if( !Vec2::Clockwise( aToPoint, aToB ) )
			return false;

		vertexA = vertexB;
	}
	return true;
}
